﻿#include "BuffDialog.h"
#include "../../MirGraphics/MLibrary.h"
#include "../../Settings.h"
#include "../../MirSounds/SoundManager.h"
#include "../GameScene.h"
#include "../../Forms/Client.CMain.h"
#include "../../../Shared/Functions/RegexFunctions.h"
#include "../../../Shared/Data/Stat.h"
#include "../../../Shared/Language.h"
#include "../../../Shared/Functions/Functions.h"

using namespace Client::MirControls;
using namespace Client::MirGraphics;
using namespace Client::MirSounds;

namespace Client::MirScenes::Dialogs
{

    BuffDialog::BuffDialog()
    {
        setIndex(20);
        setLibrary(Libraries::Prguse2);
        setMovable(false);
        Size tempVar(44, 34);
        setSize(&tempVar);
        Point tempVar2(Settings::ScreenWidth - 170, 0);
        setLocation(&tempVar2);
        setSort(true);

        setOpacity(0.0f);
        _fadedOut = true;

        _expandCollapseButton = new MirButton();
        _expandCollapseButton->setIndex(7);
        _expandCollapseButton->setHoverIndex(8);
        Size tempVar3(16, 15);
        _expandCollapseButton->setSize(&tempVar3);
        _expandCollapseButton->setLibrary(Libraries::Prguse2);
        _expandCollapseButton->setParent(this);
        _expandCollapseButton->setPressedIndex(9);
        _expandCollapseButton->setSound(SoundList::ButtonA);
        _expandCollapseButton->setOpacity(0.0f);
        _expandCollapseButton->Click += [&] (o, e)
        {
            if (_buffCount == 1)
            {
                Settings::ExpandedBuffWindow = true;
            }
            else
            {
                Settings::ExpandedBuffWindow = !Settings::ExpandedBuffWindow;
            }
    
            UpdateWindow();
        };

        _buffCountLabel = new MirLabel();
        _buffCountLabel->setParent(this);
        _buffCountLabel->setAutoSize(true);
        _buffCountLabel->setDrawFormat(TextFormatFlags::HorizontalCenter | TextFormatFlags::VerticalCenter);
        Font tempVar4(Settings::FontName, 10.0F, FontStyle::Bold);
        _buffCountLabel->setFont(&tempVar4);
        _buffCountLabel->setNotControl(true);
        _buffCountLabel->setSort(true);
        _buffCountLabel->setVisible(false);
        _buffCountLabel->setForeColour(Color::Yellow);
        _buffCountLabel->setOutLineColour(Color::Black);
    }

    void BuffDialog::CreateBuff(ClientBuff *buff)
    {
        auto buffImage = BuffImage(buff->Type);

        auto buffLibrary = Libraries::BuffIcon;

        if (buffImage >= 20000)
        {
            buffImage -= 20000;
            buffLibrary = Libraries::MagIcon;
        }

        if (buffImage >= 10000)
        {
            buffImage -= 10000;
            buffLibrary = Libraries::Prguse2;
        }

        auto image = new MirImageControl();
        image->setLibrary(buffLibrary);
        image->setParent(this);
        image->setVisible(true);
        image->setSort(false);
        image->setIndex(buffImage);

        _buffList.Insert(0, image);
        UpdateWindow();

//C# TO C++ CONVERTER TODO TASK: A 'delete image' statement was not added since image was passed to a method or constructor. Handle memory management manually.
    }

    void BuffDialog::RemoveBuff(int buffId)
    {
        _buffList[buffId]->Dispose();
        _buffList.erase(_buffList.begin() + buffId);

        UpdateWindow();
    }

    void BuffDialog::Process()
    {
        if (_buffList.size() != _buffCount)
        {
            UpdateWindow();
        }

        for (auto i = 0; i < _buffList.size(); i++)
        {
            auto image = _buffList[i];
            auto buff = GameScene::Scene->Buffs[i];

            auto buffImage = BuffImage(buff->Type);
            auto buffLibrary = Libraries::BuffIcon;

            //ArcherSpells - VampireShot,PoisonShot
            if (buffImage >= 20000)
            {
                buffImage -= 20000;
                buffLibrary = Libraries::MagIcon;
            }

            if (buffImage >= 10000)
            {
                buffImage -= 10000;
                buffLibrary = Libraries::Prguse2;
            }

            Point tempVar(getSize()->Width - 10 - 23 - (i * 23) + ((10 * 23) * (i / 10)), 6 + ((i / 10) * 24));
            image->setLocation(&tempVar);
            image->setHint(Settings::ExpandedBuffWindow ? BuffString(buff) : CombinedBuffText());
            image->setIndex(buffImage);
            image->setLibrary(buffLibrary);

            if (Settings::ExpandedBuffWindow || !Settings::ExpandedBuffWindow && i == 0)
            {
                image->setVisible(true);
                image->setOpacity(1.0f);
            }
            else
            {
                image->setVisible(false);
                image->setOpacity(0.6f);
            }

            if (buff->Infinite || !(BankersRounding::round((buff->ExpireTime - CMain::Time) / 1000) <= 5))
            {
                continue;
            }

            auto time = (buff->ExpireTime - CMain::Time) / 100;

            if (BankersRounding::round(time) % 10 < 5)
            {
                image->setIndex(-1);
            }
        }

        if (IsMouseOver(CMain::MPoint))
        {
            if (_buffCount == 0 || (!_fadedIn && CMain::Time <= _nextFadeTime))
            {
                return;
            }

            setOpacity(getOpacity() + FadeRate);
            _expandCollapseButton->setOpacity(_expandCollapseButton->getOpacity() + FadeRate);

            if (getOpacity() > 1.0f)
            {
                setOpacity(1.0f);
                _expandCollapseButton->setOpacity(1.0f);
                _fadedIn = true;
                _fadedOut = false;
            }

            _nextFadeTime = CMain::Time + FadeDelay;
        }
        else
        {
            if (!_fadedOut && CMain::Time <= _nextFadeTime)
            {
                return;
            }

            setOpacity(getOpacity() - FadeRate);
            _expandCollapseButton->setOpacity(_expandCollapseButton->getOpacity() - FadeRate);

            if (getOpacity() < 0.0f)
            {
                setOpacity(0.0f);
                _expandCollapseButton->setOpacity(0.0f);
                _fadedOut = true;
                _fadedIn = false;
            }

            _nextFadeTime = CMain::Time + FadeDelay;
        }
    }

    void BuffDialog::UpdateWindow()
    {
        _buffCount = _buffList.size();

        if (_buffCount > 0 && Settings::ExpandedBuffWindow)
        {
            auto oldWidth = getSize()->Width;

            if (_buffCount <= 10)
            {
                setIndex(20 + _buffCount - 1);
            }
            else if (_buffCount > 10)
            {
                setIndex(20 + 10);
            }
            else if (_buffCount > 20)
            {
                setIndex(20 + 11);
            }
            else if (_buffCount > 30)
            {
                setIndex(20 + 12);
            }
            else if (_buffCount > 40)
            {
                setIndex(20 + 13);
            }

            auto newX = getLocation()->X - getSize()->Width + oldWidth;
            auto newY = getLocation()->Y;
            Point tempVar(newX, newY);
            setLocation(&tempVar);

            _buffCountLabel->setVisible(false);

            Point tempVar2(getSize()->Width - 15, 0);
            _expandCollapseButton->setLocation(&tempVar2);
            Size tempVar3((_buffCount > 10 ? 10 : _buffCount) * 23, 24 + (_buffCount / 10) * 24);
            setSize(&tempVar3);
        }
        else if (_buffCount > 0 && !Settings::ExpandedBuffWindow)
        {
            auto oldWidth = getSize()->Width;

            setIndex(20);

            auto newX = getLocation()->X - getSize()->Width + oldWidth;
            auto newY = getLocation()->Y;
            Point tempVar4(newX, newY);
            setLocation(&tempVar4);

            _buffCountLabel->setVisible(true);
            _buffCountLabel->setText(StringHelper::formatSimple("{0}", _buffCount));
            Point tempVar5(getSize()->Width / 2 - _buffCountLabel->getSize()->Width / 2, getSize()->Height / 2 - 10);
            _buffCountLabel->setLocation(&tempVar5);
            _buffCountLabel->BringToFront();

            Point tempVar6(getSize()->Width - 15, 0);
            _expandCollapseButton->setLocation(&tempVar6);
            Size tempVar7(44, 34);
            setSize(&tempVar7);
        }
    }

    std::string BuffDialog::BuffString(ClientBuff *buff)
    {
//C# TO C++ CONVERTER TODO TASK: There is no C++ equivalent to 'ToString':
        std::string text = RegexFunctions::SeperateCamelCase(buff->Type.ToString()) + "\n";
        bool overridestats = false;

        switch (buff->Type)
        {
            case BuffType::GameMaster:
            {
                GMOptions options = static_cast<GMOptions>(buff->Values[0]);

                if (options::HasFlag(GMOptions::GameMaster))
                {
                    text += "-Invisible\n";
                }
                if (options::HasFlag(GMOptions::Superman))
                {
                    text += "-Superman\n";
                }
                if (options::HasFlag(GMOptions::Observer))
                {
                    text += "-Observer\n";
                }
                break;
            }
            case BuffType::MentalState:
                switch (buff->Values[0])
                {
                    case 0:
                        text += "Agressive (Full damage)\nCan't shoot over walls.\n";
                        break;
                    case 1:
                        text += "Trick shot (Minimal damage)\nCan shoot over walls.\n";
                        break;
                    case 2:
                        text += "Group Mode (Medium damage)\nDon't steal agro.\n";
                        break;
                }
                break;
            case BuffType::Hiding:
            case BuffType::ClearRing:
                text += "Invisible to many monsters.\n";
                break;
            case BuffType::MoonLight:
                text += "Invisible to players and many\nmonsters when at a distance.\n";
                break;
            case BuffType::EnergyShield:
                overridestats = true;
                text += StringHelper::formatSimple("{0}% chance to gain {1} HP when attacked.\n", buff->Stats[Stat::EnergyShieldPercent], buff->Stats[Stat::EnergyShieldHPGain]);
                break;
            case BuffType::DarkBody:
                text += "Invisible to many monsters and able to move.\n";
                break;
            case BuffType::VampireShot:
                text += "Gives you a vampiric ability\nthat can be released with\ncertain skills.\n";
                break;
            case BuffType::PoisonShot:
                text += "Gives you a poison ability\nthat can be released with\ncertain skills.\n";
                break;
            case BuffType::Concentration:
                text += "Increases chance on element extraction.\n";
                break;
            case BuffType::MagicBooster:
                overridestats = true;
                text = StringHelper::formatSimple("Increases MC by: {0}-{1}.\nIncreases consumption by {2}%.\n", buff->Stats[Stat::MinMC], buff->Stats[Stat::MaxMC], buff->Stats[Stat::ManaPenaltyPercent]);
                break;
            case BuffType::Transform:
                text = "Disguises your appearance.\n";
                break;
            case BuffType::Mentee:
                text = "Learn skill points twice as quick.\n";
                break;
            case BuffType::Guild:
                text += GameScene::Scene->GuildDialog->ActiveStats;
                break;
        }

        if (!overridestats)
        {
            for (auto val : *buff->Stats)
            {
                auto c = val->second->Value < 0 ? "Decreases" : "Increases";
//C# TO C++ CONVERTER TODO TASK: There is no C++ equivalent to 'ToString':
                auto key = val->second.Key->ToString();

                auto strKey = RegexFunctions::SeperateCamelCase(StringHelper::replace(StringHelper::replace(StringHelper::replace(key, "Rate", ""), "Multiplier", ""), "Percent", ""));

                auto sign = "";

                if (key.find("Percent") != std::string::npos)
                {
                    sign = "%";
                }
                else if (key.find("Multiplier") != std::string::npos)
                {
                    sign = "x";
                }

                auto txt = std::string::Format("{0} {1} by: {2}{3}.\n", c, strKey, val->second->Value, sign);

                text += txt;
            }
        }

        text += buff->Infinite ? GameLanguage::ExpireNever : std::string::Format(GameLanguage::Expire, Functions::PrintTimeSpanFromSeconds(BankersRounding::round((buff->ExpireTime - CMain::Time) / 1000)));

        if (!buff->Caster.empty())
        {
            text += StringHelper::formatSimple("\nCaster: {0}", buff->Caster);
        }

        return text;
    }

    std::string BuffDialog::CombinedBuffText()
    {
        std::string text = "Active Buffs\n";
        auto stats = new Stats();

        for (auto i = 0; i < _buffList.size(); i++)
        {
            auto buff = GameScene::Scene->Buffs[i];

            stats->Add(buff->Stats);
        }

        for (auto val : *stats)
        {
            auto c = val->second->Value < 0 ? "Decreased" : "Increased";
//C# TO C++ CONVERTER TODO TASK: There is no C++ equivalent to 'ToString':
            auto key = val->second.Key->ToString();

            auto strKey = RegexFunctions::SeperateCamelCase(StringHelper::replace(StringHelper::replace(StringHelper::replace(key, "Rate", ""), "Multiplier", ""), "Percent", ""));

            auto sign = "";

            if (key.find("Percent") != std::string::npos)
            {
                sign = "%";
            }
            else if (key.find("Multiplier") != std::string::npos)
            {
                sign = "x";
            }

            auto txt = std::string::Format("{0} {1} by: {2}{3}.\n", c, strKey, val->second->Value, sign);

            text += txt;
        }

//C# TO C++ CONVERTER TODO TASK: A 'delete stats' statement was not added since stats was passed to a method or constructor. Handle memory management manually.
        return text;
    }

    int BuffDialog::BuffImage(BuffType type)
    {
        switch (type)
        {
            //Skills
            case BuffType::Fury:
                return 76;
            case BuffType::Rage:
                return 49;
            case BuffType::ImmortalSkin:
                return 80;
            case BuffType::CounterAttack:
                return 7;

            case BuffType::MagicBooster:
                return 73;
            case BuffType::MagicShield:
                return 30;

            case BuffType::Hiding:
            case BuffType::ClearRing:
                return 17;
            case BuffType::Haste:
                return 60;
            case BuffType::SoulShield:
                return 13;
            case BuffType::BlessedArmour:
                return 14;
            case BuffType::ProtectionField:
                return 50;
            case BuffType::UltimateEnhancer:
                return 35;
            case BuffType::Curse:
                return 45;
            case BuffType::EnergyShield:
                return 57;

            case BuffType::SwiftFeet:
                return 67;
            case BuffType::LightBody:
                return 68;
            case BuffType::MoonLight:
                return 65;
            case BuffType::DarkBody:
                return 70;

            case BuffType::Concentration:
                return 96;
            case BuffType::VampireShot:
                return 100;
            case BuffType::PoisonShot:
                return 102;
            case BuffType::MentalState:
                return 199;

            //Monster
            case BuffType::RhinoPriestDebuff:
                return 217;

            //Special
            case BuffType::GameMaster:
                return 173;
            case BuffType::General:
                return 182;
            case BuffType::Exp:
                return 260;
            case BuffType::Drop:
                return 162;
            case BuffType::Gold:
                return 168;
            case BuffType::Knapsack:
            case BuffType::BagWeight:
                return 235;
            case BuffType::Transform:
                return 241;
            case BuffType::Mentor:
                return 248;
            case BuffType::Mentee:
                return 248;
            case BuffType::RelationshipEXP:
                return 201;
            case BuffType::Guild:
                return 203;
            case BuffType::Rested:
                return 240;
            case BuffType::TemporalFlux:
                return 261;
            case BuffType::Skill:
                return 200;

            //Stats
            case BuffType::Impact:
                return 249;
            case BuffType::Magic:
                return 165;
            case BuffType::Taoist:
                return 250;
            case BuffType::Storm:
                return 170;
            case BuffType::HealthAid:
                return 161;
            case BuffType::ManaAid:
                return 169;
            case BuffType::Defence:
                return 166;
            case BuffType::MagicDefence:
                return 158;
            case BuffType::WonderDrug:
                return 252;
            default:
                return 0;
        }
    }
}
